package reports.display;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

/**
 * Holds the data for a single row in a report table.
 * 
 * @see ReportTable
 * @see ReportTable#createRow()
 * 
 * @author Ryan Cheatham
 * 
 *         {@invariant getColumnCount() > 0}
 */
public class ReportTableRow
{

  private final String[]    contents;
  private final ReportTable table;

  /**
   * Constructs a new table row with empty contents
   * 
   * @param columns
   *          the number of columns in the row
   * 
   * @see ReportTable#createRow()
   */
  // NOTE TO GROUP: do not change visibility of this constructor! It is for the ReportTable class
  // only
  ReportTableRow(ReportTable table, int columns)
  {
    contents = new String[columns];
    this.table = table;
  }

  /**
   * Gets the table that this row was created by
   */
  // NOTE TO GROUP: do not change visibility of this method! It is for the ReportTable class only
  ReportTable getTable()
  {
    return table;
  }

  /**
   * Returns the number of columns in this row
   */
  public int getColumnCount()
  {
    return contents.length;
  }

  /**
   * Gets the text content of the specified cell
   * 
   * @param cell
   *          The index of the cell
   * @return The text content of the specified cell
   * 
   *         {@pre 0 <= cell < getColumnCount()}
   * 
   * @throws IndexOutOfBoundsException
   *           if cell < 0 or cell >= getColumnCount()
   */
  public String getCell(int cell)
  {
    return contents[cell];
  }

  /**
   * Gets an iterator through all the cells in this row.
   * 
   * {@post retval != null}
   * 
   * {@post retval.hasNext() == true (before retval.next() is called)}
   */
  public Iterator<String> getCells()
  {
    return Collections.unmodifiableList(Arrays.asList(contents)).iterator();
  }

  /**
   * Sets the text content of the specified cell. This method uses the {@link Object#toString()}
   * method to set the actual textual content of the cell.
   * 
   * @param cell
   *          The index of the cell.
   * @param content
   *          The new content of the specified cell.
   * 
   *          {@pre 0 <= cell < getColumnCount()}
   * 
   *          {@pre content != null}
   * 
   * @throws IndexOutOfBoundsException
   *           if cell < 0 or cell >= getColumnCount()
   * @throws NullPointerException
   *           if content is null
   */
  public void setCell(int cell, Object content)
  {
    setCell(cell, content.toString());
  }

  /**
   * Sets the text content of the specified cell
   * 
   * @param cell
   *          The index of the cell.
   * @param content
   *          The new text content of the specified cell.
   * 
   *          {@pre 0 <= cell < getColumnCount()}
   * 
   *          {@pre content != null}
   * 
   * @throws IndexOutOfBoundsException
   *           if cell < 0 or cell >= getColumnCount()
   * @throws NullPointerException
   *           if content is null
   */
  public void setCell(int cell, String content)
  {
    if (content == null)
      throw new NullPointerException();

    contents[cell] = content;
  }

  @Override
  public String toString()
  {
    StringBuilder builder = new StringBuilder();
    builder.append("ReportTableRow [table='");
    builder.append(table.getTitle());
    builder.append("', contents=");
    builder.append(Arrays.toString(contents));
    builder.append("]");
    return builder.toString();
  }

  @Override
  public int hashCode()
  {
    final int prime = 31;
    int result = 1;
    result = prime * result + Arrays.hashCode(contents);
    result = prime * result + ((table == null) ? 0 : table.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj)
  {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (!(obj instanceof ReportTableRow))
      return false;
    ReportTableRow other = (ReportTableRow) obj;
    if (!Arrays.equals(contents, other.contents))
      return false;
    if (table == null)
    {
      if (other.table != null)
        return false;
    }
    else if (!table.equals(other.table))
      return false;
    return true;
  }
}
